using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.IO;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using Color=System.Drawing.Color;
using PixelFormat=System.Drawing.Imaging.PixelFormat;

namespace MimeCloud.GDI.Imaging
{
    public class Resize
    {
        public enum Dimensions
        {
            Width,
            Height
        }
        public enum AnchorPosition
        {
            Top,
            Center,
            Bottom,
            Left,
            Right
        }
        public enum ResizeType
        {
            ResizeExactAndFit,
            ResizeExactAndCrop,
            ResizeResolutionAndFit,
            ResizeResolutionAndCrop
        }

        public static Image ScaleByPercent(Image imgPhoto, int Percent)
        {
            float nPercent = ((float)Percent / 100);

            int sourceWidth = imgPhoto.Width;
            int sourceHeight = imgPhoto.Height;
            int sourceX = 0;
            int sourceY = 0;

            int destX = 0;
            int destY = 0;
            int destWidth = (int)(sourceWidth * nPercent);
            int destHeight = (int)(sourceHeight * nPercent);

            Bitmap bmPhoto = new Bitmap(destWidth, destHeight, PixelFormat.Format24bppRgb);
            bmPhoto.SetResolution(imgPhoto.HorizontalResolution, imgPhoto.VerticalResolution);

            Graphics grPhoto = Graphics.FromImage(bmPhoto);
            grPhoto.InterpolationMode = InterpolationMode.HighQualityBicubic;

            grPhoto.DrawImage(imgPhoto,
                new Rectangle(destX, destY, destWidth, destHeight),
                new Rectangle(sourceX, sourceY, sourceWidth, sourceHeight),
                GraphicsUnit.Pixel);

            grPhoto.Dispose();
            return bmPhoto;
        }
        public static Image ConstrainProportions(Image imgPhoto, int Size, Dimensions Dimension)
        {
            int sourceWidth = imgPhoto.Width;
            int sourceHeight = imgPhoto.Height;
            int sourceX = 0;
            int sourceY = 0;
            int destX = 0;
            int destY = 0;
            float nPercent = 0;

            switch (Dimension)
            {
                case Dimensions.Width:
                    nPercent = ((float)Size / (float)sourceWidth);
                    break;
                default:
                    nPercent = ((float)Size / (float)sourceHeight);
                    break;
            }

            int destWidth = (int)(sourceWidth * nPercent);
            int destHeight = (int)(sourceHeight * nPercent);

            Bitmap bmPhoto = new Bitmap(destWidth, destHeight, PixelFormat.Format24bppRgb);
            bmPhoto.SetResolution(imgPhoto.HorizontalResolution, imgPhoto.VerticalResolution);

            Graphics grPhoto = Graphics.FromImage(bmPhoto);
            grPhoto.InterpolationMode = InterpolationMode.HighQualityBicubic;

            grPhoto.DrawImage(imgPhoto,
            new Rectangle(destX, destY, destWidth, destHeight),
            new Rectangle(sourceX, sourceY, sourceWidth, sourceHeight),
            GraphicsUnit.Pixel);

            grPhoto.Dispose();
            return bmPhoto;
        }

        public static Image FixedSize(Image imgPhoto, int Width, int Height)
        {
            return FixedSize(imgPhoto, Width, Height, Color.Empty);
        }

        public static Image FixedSize(Image imgPhoto, int Width, int Height, Color backColor)
        {
            return FixedSize(imgPhoto, Width, Height, backColor, ResizeType.ResizeExactAndFit, false);
        }

        public static Image FixedSize(Image imgPhoto, int Width, int Height, Color backColour, ResizeType actionType, bool preview)
        {
            int sourceWidth = imgPhoto.Width;
            int sourceHeight = imgPhoto.Height;

            int sourceX = 0;
            int sourceY = 0;
            int destX = 0;
            int destY = 0;

            float nPercent = 0;
            float nPercentW = 0;
            float nPercentH = 0;

            nPercentW = ((float)Width / (float)sourceWidth);
            nPercentH = ((float)Height / (float)sourceHeight);

            Dimensions paddingMode;
            //if we have to pad the height pad both the top and the bottom
            //with the difference between the scaled height and the desired height
            if (
                (actionType == ResizeType.ResizeExactAndFit && nPercentH < nPercentW)
                ||
                (actionType == ResizeType.ResizeExactAndCrop && nPercentH > nPercentW)
                )
            {
                paddingMode = Dimensions.Width;
                nPercent = nPercentH;
                destX = (int)((Width - (sourceWidth * nPercent)) / 2);
            }
            else
            {
                paddingMode = Dimensions.Height;
                nPercent = nPercentW;
                destY = (int)((Height - (sourceHeight * nPercent)) / 2);
            }



            int destWidth = (int)(sourceWidth * nPercent);
            int destHeight = (int)Math.Round((sourceHeight * nPercent));

            //if (actionType==ResizeType.ResizeExactAndCrop)
            //{
            //    //find smallest resolution that fits entire image in canvas
            //    if (destHeight<Height && destWidth>=Width)
            //    {

            //    }
            //}

            //prepare some image attributes for gdi drawing
            ImageAttributes attr = new ImageAttributes();
            attr.SetWrapMode(WrapMode.TileFlipXY);

            //resize image (without the padding first)
            Bitmap bmpTemp = new Bitmap(destWidth, destHeight);
            bmpTemp.SetResolution(imgPhoto.HorizontalResolution, imgPhoto.VerticalResolution);
            Graphics grTemp = Graphics.FromImage(bmpTemp);

            if (!preview)
            {
                grTemp.InterpolationMode = InterpolationMode.HighQualityBicubic;
                grTemp.PixelOffsetMode = PixelOffsetMode.HighQuality;
            }
            else
            {
                grTemp.InterpolationMode = InterpolationMode.Bilinear;
                grTemp.PixelOffsetMode = PixelOffsetMode.HighSpeed;
            }
            grTemp.DrawImage(imgPhoto,
                new Rectangle(0, 0, destWidth, destHeight),
                0, 0, imgPhoto.Width, imgPhoto.Height, GraphicsUnit.Pixel,
                attr);

            //prepare canvas with required resolution
            Bitmap bmPhoto = new Bitmap(Width, Height, PixelFormat.Format24bppRgb);
            bmPhoto.SetResolution(imgPhoto.HorizontalResolution, imgPhoto.VerticalResolution);
            Graphics grPhoto = Graphics.FromImage(bmPhoto);

            //draw the background of the canvas
            if (backColour == Color.Empty)
            {
                //get sample of image to repeat in blank areas
                Rectangle textureRect;
                if (paddingMode == Dimensions.Width)
                    textureRect = new Rectangle(1, 0, 2, bmpTemp.Height);
                else
                    textureRect = new Rectangle(0, 1, bmpTemp.Width, 2);

                int whiteComparison1 =
                    Helper.CompareColours(bmpTemp.GetPixel(textureRect.Left, textureRect.Top), Color.White);
                //fill canvas with texture
                if (whiteComparison1 <= 1)
                {
                    TextureBrush brush = new TextureBrush(bmpTemp, WrapMode.Tile, textureRect);
                    grPhoto.FillRectangle(brush, 0, 0, Width, Height);
                }
                else
                    grPhoto.Clear(Color.White);
            }
            else
                grPhoto.Clear(backColour);

            //draw the resized image on to the canvas
            if (!preview)
            {
                grPhoto.InterpolationMode = InterpolationMode.HighQualityBilinear;
                grPhoto.PixelOffsetMode = PixelOffsetMode.HighQuality;
            }
            else
            {
                grPhoto.InterpolationMode = InterpolationMode.Bilinear;
                grPhoto.PixelOffsetMode = PixelOffsetMode.HighSpeed;
            }
            grPhoto.DrawImage(bmpTemp,
                new Rectangle(destX, destY, destWidth, destHeight),
                0, 0, bmpTemp.Width, bmpTemp.Height,
                GraphicsUnit.Pixel, attr);
            //bmPhoto = Filters.UnsharpMasker.UnsharpMask(bmPhoto.Clone() as Bitmap, 200.0, 15, 50);
            //clean up
            grTemp.Dispose();
            grPhoto.Dispose();
            bmpTemp.Dispose();

            //filters


            //return new image
            return bmPhoto;
        }
        public static Image Crop(Image imgPhoto, int Width, int Height, AnchorPosition Anchor)
        {
            int sourceWidth = imgPhoto.Width;
            int sourceHeight = imgPhoto.Height;
            float nPercent = 0;
            float nPercentW = ((float)Width / (float)sourceWidth);
            float nPercentH = ((float)Height / (float)sourceHeight);

            int destY = 0;
            int destX = 0;

            if (nPercentH < nPercentW)
            {
                nPercent = nPercentW;
                switch (Anchor)
                {
                    case AnchorPosition.Top:
                        destY = 0;
                        break;
                    case AnchorPosition.Bottom:
                        destY = (int)(Height - (sourceHeight * nPercent));
                        break;
                    default:
                        destY = (int)((Height - (sourceHeight * nPercent)) / 2);
                        break;
                }
            }
            else
            {
                nPercent = nPercentH;
                switch (Anchor)
                {
                    case AnchorPosition.Left:
                        destX = 0;
                        break;
                    case AnchorPosition.Right:
                        destX = (int)(Width - (sourceWidth * nPercent));
                        break;
                    default:
                        destX = (int)((Width - (sourceWidth * nPercent)) / 2);
                        break;
                }
            }

            return Crop(imgPhoto, Width, Height, destX, destY);
        }

        public static Image Crop(Image imgPhoto, Rectangle croppableArea)
        {
            return Crop(imgPhoto, croppableArea, false);
        }

        public static Image Crop(Image imgPhoto, Rectangle croppableArea, bool preview)
        {
            return Crop(imgPhoto, croppableArea.Width, croppableArea.Height, croppableArea.Left, croppableArea.Top, preview);
        }

        public static Image Crop(Image imgPhoto, int Width, int Height, int x, int y)
        {
            return Crop(imgPhoto, Width, Height, x, y, false);
        }

        public static Image Crop(Image imgPhoto, int Width, int Height, int x, int y, bool preview)
        {
            //new bitmap
            Bitmap bmPhoto = new Bitmap(Width, Height, PixelFormat.Format24bppRgb);
            bmPhoto.SetResolution(imgPhoto.HorizontalResolution, imgPhoto.VerticalResolution);

            //graphics based on bitmap
            Graphics grPhoto = Graphics.FromImage(bmPhoto);
            if (!preview)
            {
                grPhoto.InterpolationMode = InterpolationMode.HighQualityBilinear;
                grPhoto.PixelOffsetMode = PixelOffsetMode.HighQuality;
            }
            else
            {
                grPhoto.InterpolationMode = InterpolationMode.Bilinear;
                grPhoto.PixelOffsetMode = PixelOffsetMode.HighSpeed;
            }
            //draw portion of original image on new bitmap using the graphics
            grPhoto.DrawImage(imgPhoto,
                new Rectangle(0, 0, Width, Height),
                new Rectangle(x, y, Width, Height),
                GraphicsUnit.Pixel);

            //clean-up and return
            grPhoto.Dispose();
            return bmPhoto;
        }


        /// <summary>
        /// Creates an image from the image data according to the size specified. To preserve aspect ratio, set either the width or the height to 0
        /// </summary>
        /// <param name="imageData"></param>
        /// <param name="decodePixelWidth"></param>
        /// <param name="decodePixelHeight"></param>
        /// <returns></returns>
        public static ImageSource CreateImage(byte[] imageData, int decodePixelWidth, int decodePixelHeight)
        {
            if (imageData == null) return null;

            BitmapImage result = new BitmapImage();
            
            result.BeginInit();
            if (decodePixelWidth > 0)
            {
                result.DecodePixelWidth = decodePixelWidth;
            }

            if (decodePixelHeight > 0)
            {
                result.DecodePixelHeight = decodePixelHeight;
            }
            
            result.StreamSource = new MemoryStream(imageData);

            result.CreateOptions = BitmapCreateOptions.None;

            result.CacheOption = BitmapCacheOption.Default;

            result.EndInit();

            return result;
        }


        /// <summary>
        /// Saves a bitmap to a file
        /// </summary>
        /// <param name="image"></param>
        /// <param name="preferredFormat"></param>
        /// <returns></returns>
        public static byte[] GetEncodedImageData(ImageSource image, string preferredFormat)
        {
            byte[] result = null;

            BitmapEncoder encoder = null;

            switch (preferredFormat.ToLower())
            {
                case ".jpg":
                case ".jpeg":
                    encoder = new JpegBitmapEncoder();
                    (encoder as JpegBitmapEncoder).QualityLevel = 90;
                    break;

                case ".bmp":
                    encoder = new BmpBitmapEncoder();
                    break;

                case ".png":
                    encoder = new PngBitmapEncoder();
                    break;

                case ".tif":
                case ".tiff":
                    encoder = new TiffBitmapEncoder();
                    break;

                case ".gif":
                    encoder = new GifBitmapEncoder();
                    break;

                case ".wmp":
                    encoder = new WmpBitmapEncoder();
                    break;
            }
            

            if (image is BitmapSource)
            {
                MemoryStream stream = new MemoryStream();
                encoder.Frames.Add(BitmapFrame.Create(image as BitmapSource));
                encoder.Save(stream);
                stream.Seek(0, SeekOrigin.Begin);
                result = new byte[stream.Length];
                BinaryReader br = new BinaryReader(stream);
                br.Read(result, 0, (int) stream.Length);
                br.Close();
                stream.Close();

            }

            return result;

        }

    }
}
